package com.liangchen.astestpanel;

import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.view.Window;
import android.widget.Button;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;

import com.liangchen.astools.AsDebugPanel;
import com.liangchen.astools.utils.AsLog;

import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;


public class MainActivity extends AppCompatActivity {
    Button btnTest;

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
    }

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    private void initViews() {
        btnTest = findViewById(R.id.btn_test);
      /*  btnTest.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.KITKAT)
            @Override
            public void onClick(View v) {
                //AsP≈erfManager.hookChoreographer();
            }
        });*/
        // hookWindowSession();
        btnTest.setOnClickListener(v -> startActivity(new Intent(MainActivity.this, AsDebugPanel.class)));
    }

    private static List<Object> mInstanceRoots;
    private static Object mInstanceWMG;
    private static Class<?> mClassWMG;

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    public void hookWindowSession() {
        try {
            mClassWMG = Class.forName("android.view.WindowManagerGlobal");
            Method getInstanceMethod = mClassWMG.getDeclaredMethod("getInstance");
            mInstanceWMG = getInstanceMethod.invoke(null);

            Method getWindowSessionMethod = mClassWMG.getDeclaredMethod("getWindowSession");
            Object iWindowSession = getWindowSessionMethod.invoke(null);

            Field field = mClassWMG.getDeclaredField("sWindowSession");
            field.setAccessible(true);
            Object windowSessionProxy = field.get(null);
            windowSessionProxy = Proxy.newProxyInstance(this.getApplication().getClass().getClassLoader(),
                    windowSessionProxy.getClass().getInterfaces(), new HookedWindowSession(windowSessionProxy));
            field.set(iWindowSession, windowSessionProxy);

            Field mFieldRoots = mClassWMG.getDeclaredField("mRoots");
            mFieldRoots.setAccessible(true);
            mInstanceRoots = (List<Object>) mFieldRoots.get(mInstanceWMG);
            AsLog.i("cdgtesthook", "mInstanceRoots" + mInstanceRoots);

        } catch (ClassNotFoundException | NoSuchMethodException e) {
            AsLog.i("cdgtesthook", e.toString());
        } catch (IllegalAccessException e) {
            AsLog.i("cdgtesthook", e.toString());
        } catch (InvocationTargetException e) {
            AsLog.i("cdgtesthook", e.toString());
        } catch (NoSuchFieldException e) {
            AsLog.i("cdgtesthook", e.toString());
        }
    }

    public class HookedWindowSession implements InvocationHandler {
        private Object mWindowSessionObj;

        public HookedWindowSession(Object windowSessionObj) {
            this.mWindowSessionObj = windowSessionObj;
        }

        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object invoke = method.invoke(mWindowSessionObj, args);
            if (method.getName().equals("addToDisplay")) {
               Window window = getWindowFromArgs(args[0]);
                AsLog.i("cdgtesthook", "addToDisplay window >>:" + window.getAttributes().getTitle() + ",visable:" + args[3]);
            }
            if (method.getName().equals("remove")) {
                Window window = getWindowFromArgs(args[0]);
                AsLog.i("cdgtesthook", "remove window <<:"+window.getAttributes().getTitle());
            }

            if (method.getName().equals("relayout")) {
                Window window = getWindowFromArgs(args[0]);
                AsLog.i("cdgtesthook", "relayout window <<:" + window.getAttributes().getTitle() + " visable：" + args[5]);
            }
            return invoke;
        }
    }


    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    private Window getWindowFromArgs(Object arg){
        Window window = null;
        Field fieldViewAncestor = null;
        try {
            fieldViewAncestor = arg.getClass().getDeclaredField("mViewAncestor");

        fieldViewAncestor.setAccessible(true);
        WeakReference weakReference = (WeakReference)fieldViewAncestor.get(arg);
        Object viewRootIpml = weakReference.get();

        Field fieldView = viewRootIpml.getClass().getDeclaredField("mView");
        fieldView.setAccessible(true);
        Object decorView = fieldView.get(viewRootIpml);

        if (!decorView.getClass().getName().contains("DecorView")) {
            AsLog.i("cdgtesthook", "ERR: not contain DecorView:" + decorView);
            return null;
        }

        Field fieldWindow = decorView.getClass().getDeclaredField("mWindow");
        fieldWindow.setAccessible(true);
        window = (Window) fieldWindow.get(decorView);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return window;
    }

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    private Window getCurrentWindow() {
        Window window = null;
        Object viewRootIpml = null;
        if (mInstanceRoots != null) {
            int lastIndex = mInstanceRoots.size() - 1;
            viewRootIpml = mInstanceRoots.get(lastIndex);
        }

        Field view = null;
        try {
            view = viewRootIpml.getClass().getDeclaredField("mView");

            view.setAccessible(true);
            Object decorView = view.get(viewRootIpml);

            if (!decorView.getClass().getName().contains("DecorView")) {
                AsLog.i("cdgtesthook", "ERR: not contain DecorView:" + decorView);
                return null;
            }

            Field fieldWindow = decorView.getClass().getDeclaredField("mWindow");
            fieldWindow.setAccessible(true);
            window = (Window) fieldWindow.get(decorView);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return window;
    }
}